#ifndef _CIRCUIT_GRAPH_H
#define _CIRCUIT_GRAPH_H

#include "extendedtimingparser.h"
#include "extendedlibparser.h"
#include "parser_helper.h"
#include "graphModel.h"
#include <algorithm>

struct StoreOutCapacitance
{
	ostream& StoreFunction (ostream& out, std::string cellName, double min, double max)
	{	
		out << cellName << "\t" << min << "\t" << max << endl ;
		return out ;
	}
} ;

struct NodeSlackStruct {

	vertex_descriptor vertexDescriptor ;
	double			  negativeSlack ;
};

struct sortingFunction {
	bool operator() (const NodeSlackStruct& i, const NodeSlackStruct& j) const { 
		return i.negativeSlack > j.negativeSlack ;
	}
} ;


struct delaySorting {
	bool operator() (const GateDelayStructure& i, const GateDelayStructure& j) 
	{
		if (i.avgDelay > j.avgDelay)
			return true ;
	}
} ;

struct leakageSorting {
	bool operator() (const GateDelayStructure& i, const GateDelayStructure& j) 
	{
		if (i.leakagePower < j.leakagePower)
			return true ;
	}
} ;


struct delayPerLeakageSorting {
	bool operator() (const GateDelayStructure& i, const GateDelayStructure& j) 
	{
		if ((i.avgDelay/i.leakagePower) > (j.avgDelay/j.leakagePower))
			return true ;
	}
} ;

struct RegionStruct
{
	double minBound ;
	double maxBound ;
	std::vector<GateDelayStructure> cellNames ;
} ;


struct RegionComparison
{
	bool operator() (const RegionStruct& i, const RegionStruct& j)
	{
		return i.cellNames.size() < j.cellNames.size() ;
	}
};

class CircuitGraph: public boostGraph												
{
  public:
	
        // Print the property of the edge (Name, Parasitic Load, fromPin, toPin)
        void printOutEdgeProperty (vertex_descriptor&) ;	
        // Update the connectivity between cells
        void updateConnectivity (std::vector<netConnectivity>&, std::map<std::string, double>&) ;
		
        // Calculate the total leakage power of graph
        double accumTotalLeakage (std::map <std::string, LibParserCellInfo>&) ;
        double calculateTotalOutputCap (vertex_descriptor, ExtendedLibParser&) ;
        
        int findVertexIndex (std::string) ;
        int updateLevels(vertex_descriptor currNode, int inputLevel) ;
        // Find all path between the first item in the second argument (source) and first argument (target)
        void findAllPaths (vertex_descriptor, std::vector<vertex_descriptor>&, std::vector<std::vector<std::string> >&) ;
        // Returns the index of a vertex specified by the instance name
        void fillPinTrans(vertex_descriptor, 
                          ExtendedTimingParser&, 
                          ExtendedLibParser&, 
                          std::map<std::string, double>&,
                          std::map<std::string, double>&
                ) ;
		
        void pathTiming(std::vector<vertex_descriptor>&, ExtendedLibParser&, 
                        ExtendedTimingParser&, 
                        double& fallSlew, double& riseSlew,
                        double& fallArrival, double& riseArrival,
                        double& totalCapViol,  double& totalSlewViol,
                        double& totalSlackViol) ;
        
        void fillNoCapViolationCells (ExtendedLibParser&) ;
        void updateLevelDistance() ;

        int updateVertexLevels(vertex_descriptor currNode, int inputLevel, bool) ;
        int updateVertexDistance(vertex_descriptor currNode, int inputDistance, bool) ;
        
        void clearIsFixedFlag();
        void updateSortedNoCapViolation(ExtendedLibParser& library) ;
        void updateSizes() ;
        // Check whether first type cover the second type at this specific capacitance or not
        // True: if first type has both lower leakage and lower delay
        // False: otherwise
        bool isCover (std::string, std::string, double, ExtendedLibParser&, bool&) ;
        bool isCoverRange (std::string, std::string, double, double, int, ExtendedLibParser&, bool&) ;
        
        void stepSampleGateAngle (vertex_descriptor currNode, ExtendedLibParser& library, int Nsample, 
                                  std::vector<std::string>& samples, double minDelay, double maxDelay, bool& equal);
        
        void sampleGateAngleGreedy (vertex_descriptor currNode, ExtendedLibParser& library, int Nsample, std::vector<std::string>& samples
                                    , double minDelay, double maxDelay, bool& equal);
        
        void SampleGateNearby (vertex_descriptor currNode, std::string cellName, ExtendedLibParser& library, int Nsample,
                               std::vector<std::string>& samples, double minDelay, double maxDelay, bool& equal);

        // Prune the gate specified by the first argument
        void pruneGate (vertex_descriptor, ExtendedLibParser&);
        void printNodeSlackVector();
        void upSizeCap(ExtendedLibParser& library, bool&) ;
        
        int fixCones(vertex_descriptor currNode) ;
        int findMaxOrderedIndex (std::vector<std::vector<std::string> >&) ;
        int upsizeCells(double percentage, int& numberofCellChanged, std::ofstream&);
        
        double calculateTotalCapViolation(ExtendedLibParser& library,std::ofstream& capViolation);
        double calculateCapViolation(vertex_descriptor currNode, ExtendedLibParser& library);
        double findMinTotalOutputCapacitance(vertex_descriptor, ExtendedLibParser&) ;

        // Find the best candidate in terms of closeness to avg of a range
        void fillOrderedSamples(std::vector<std::pair<std::string, double> >&, double, double, std::vector<std::string>& ) ;
		
        // Sample Gate Delay
        void sampleGateDelay (vertex_descriptor, ExtendedLibParser&, int, std::vector<std::string>&) ;
		
        // Sample Gate Leakage
        void sampleGateLeakage (vertex_descriptor, ExtendedLibParser&, int, std::vector<std::string>&) ;
		
        // Sample Angular
        void sampleGateAngle (vertex_descriptor currNode, ExtendedLibParser& library, int Nsample, std::vector<std::string>& samples
                              , double minDelay, double maxDelay, bool& equal);
		
        // Store the min and max output capacitance in each node
        void updateMinMaxOutputCap (ExtendedLibParser&, StoreOutCapacitance, ostream&, bool) ;		
		
        double calTotalNegativeSlacksPerFanout(vertex_descriptor currNode, ExtendedLibParser& library, ExtendedTimingParser& timing) ;
        double calTotalNegativeSlacksTimesFanout(vertex_descriptor currNode, ExtendedLibParser& library, ExtendedTimingParser& timing) ;	
        double calTotalPositiveSlacksPerFanout(vertex_descriptor currNode, ExtendedLibParser& library, ExtendedTimingParser& timing);
        
        void   updateNodeSlackVector(ExtendedLibParser& library, ExtendedTimingParser& timing,bool) ;
        void   updatePosititveNodeSlackVector(ExtendedLibParser& library, ExtendedTimingParser& timing);
        void   downSize(double percentage, int& numberofCellChanged);
        void   readSizerFile(std::ifstream& in);
        void   clearTouchedFlag();
                
        void fillCellSizes() ;	
        void updateOutputTiming(vertex_descriptor, vertex_descriptor,
                                ExtendedLibParser&, 
                                ExtendedTimingParser&,
                                double riseTT, double fallTT) ;
		
        // Finds the range of output capacitance for each vertex
        void findRangeOutputCap (vertex_descriptor, double&, double&, ExtendedLibParser&) ;
        void downloadBestSolution();
        void fillBestSolution();
        void showNodesUnderInspection();
        // instance, cellname
	
        // Template Functions
        template <typename T, typename Bundle> std::vector<vertex_descriptor> getVerticesWithProperty(T, T Bundle::*) ;
        template <typename T, typename Bundle> std::vector<edge_descriptor> getEdgesWithProperty(T, T Bundle::*);	
        template <typename T, typename Bundle> void printGateProperty (T Bundle::*) ;
        template <typename T, typename Bundle> void printNetProperty (T Bundle::*) ;
	
        int mode;
        
        std::string nextCell(vertex_descriptor currNode) ;
        std::string previousCell(vertex_descriptor currNode);

        vector<vertex_descriptor> nodes_under_inspection;
        std::map<vertex_descriptor, std::string> bestSolution ;
        
        std::vector<std::string> cellSizes ;
        std::vector<NodeSlackStruct>  nodeSlackVector ;
        
        void operator << (const vertex_descriptor&) ;
        void operator << (const edge_descriptor&); 
};

//#include "circuitgraph.hpp"
#endif
